package com.drink.yan.svc.service;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.drink.yan.core.mapper.*;
import com.drink.yan.domain.YanUserDo;
import com.drink.yan.intf.define.YanCheckStatusE;
import com.drink.yan.intf.define.YanOpSourceStatusE;
import com.drink.yan.intf.define.YanUserBindTypeE;
import com.drink.yan.intf.entity.*;
import com.drink.yan.intf.entity.io.YanJsonMapIo;
import com.drink.yan.intf.vo.*;
import com.drink.yan.job.YanUserDataAuthParseJob;
import com.drink.yan.web.rest.req.DataTypeAuthIo;
import com.drink.yan.web.rest.req.cmd.*;
import com.drink.yan.web.rest.req.qry.*;
import com.github.meixuesong.aggregatepersistence.Aggregate;
import com.github.meixuesong.aggregatepersistence.AggregateFactory;
import com.github.meixuesong.aggregatepersistence.DataObjectUtils;
import com.meta.act.app.service.ISysConfigService;
import com.meta.act.app.service.ISysDictTypeService;
import com.meta.act.app.service.ISysUserService;
import com.meta.act.app.system.mapper.SysUserMapper;
import com.meta.act.app.tenant.entity.TenantBase;
import com.meta.act.entity.SysDictData;
import com.meta.framework.act.entity.SysUser;
import com.meta.framework.common.exception.BaseException;
import com.meta.framework.common.utils.SecurityUtils;
import com.meta.framework.common.utils.StringUtils;
import com.meta.framework.define.DelFlagEnum;
import com.meta.framework.manager.AsyncManager;
import com.meta.framework.manager.factory.AsyncFactory;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

/**
 * java类简单作用描述
 *
 * @Title:
 * @Package: com.drink.yan.svc.service.
 * @Author: M.simple
 * @Remark: The modified content
 * @CreateDate: 2023-11-25 11:52
 * @Version: v2.0
 */
@Slf4j
@Service
public class YanUserService extends ServiceImpl<YanUserDetailMapper, YanUserDetail> {

	@Resource
	private YanUserStudentMapper yanUserStudentMapper;

	@Resource
	private SysUserMapper sysUserMapper;

	@Resource
	private YanUserSeniorMapper yanUserSeniorMapper;

	@Resource
	private YanUserTeacherMapper yanUserTeacherMapper;

	@Resource
	private YanUserCounselorMapper yanUserCounselorMapper;

	@Resource
	private YanUserAgencyMapper yanUserAgencyMapper;

	@Resource
	private YanUserBindMapper yanUserBindMapper;

	@Resource
	private YanUserDetailMapper yanUserDetailMapper;

	@Resource
	private ISysDictTypeService iSysDictDataService;

	@Resource
	private ISysConfigService iSysConfigService;

	@Resource
	private ISysUserService iSysUserService;

	@Resource
	private YanSchoolService yanSchoolService;

	@Resource
	private SpecialService specialService;

	@Resource
	private YanUserCommuLogMapper yanUserCommuLogMapper;

	@Resource
	private ISysDictTypeService sysDictTypeService;

	@Resource
	private YanUserDataAuthParseJob yanUserDataAuthParseJob;


	public Aggregate<YanUserDo> getYanUserDo(String mobile) {

		SysUser user = getSysUserByMobile(mobile);

		if(Objects.isNull(user)){
			return AggregateFactory.createAggregate(new YanUserDo());
		}

		return getYanUserDo(user.getUserId());

	}

	private SysUser getSysUserByMobile(String mobile) {

		LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(SysUser::getPhonenumber, mobile);
		queryWrapper.eq(SysUser::getDelFlag, 0);
		return sysUserMapper.selectOne(queryWrapper);
	}

	public UserVo getYanUserVo(Long userId) {
		Aggregate<YanUserDo> yanUserDo = getYanUserDo(userId);

		YanUserDo root = yanUserDo.getRoot();
		UserVo userVo = root.transform(UserVo.class);

		if (Objects.nonNull(userVo.getYanUserStudent())) {
			UserBindVo userBind = getUserBind(YanUserBindTypeE.agency.getCode(), userId);
			userVo.getYanUserStudent().setAgencyUserId(userBind.getTargetUid());
			userVo.getYanUserStudent().setAgencyUserName(userBind.getTargetUidName());
			userVo.getYanUserStudent().setBindAgencyTime(userBind.getCreateTime());
			userVo.getYanUserStudent().setBindAgencyStatus(userBind.getBindStatus());

			UserBindVo teacherBind = getUserBind(YanUserBindTypeE.teacher.getCode(), userId);
			userVo.getYanUserStudent().setTeacherUserId(teacherBind.getTargetUid());
			userVo.getYanUserStudent().setTeacherUserName(teacherBind.getTargetUidName());

			UserBindVo counselorBind = getUserBind(YanUserBindTypeE.counselor.getCode(), userBind.getTargetUid());
			userVo.getYanUserStudent().setCounselorUserId(counselorBind.getTargetUid());
			userVo.getYanUserStudent().setCounselorUserName(counselorBind.getTargetUidName());
		}

		if (Objects.nonNull(userVo.getYanUserAgency())) {
			UserBindVo counselorBind = getUserBind(YanUserBindTypeE.counselor.getCode(), userId);
			userVo.getYanUserAgency().setCounselorUserId(counselorBind.getTargetUid());
			userVo.getYanUserAgency().setCounselorUserName(counselorBind.getTargetUidName());
		}

		return userVo;
	}


	public Aggregate<YanUserDo> getYanUserDo(Long userId) {

		Aggregate<YanUserDo> aggregate = AggregateFactory.createAggregate(new YanUserDo());
		if (Objects.isNull(userId)) {
			return aggregate;
		}

		SysUser sysUser = sysUserMapper.selectById(userId);
		YanUserDo userDo = sysUser.transform(YanUserDo.class);
		CompletableFuture<YanUserDetail> yanDetail = getYanDetail(userId);
		CompletableFuture<YanUserSenior> yanSenior = getYanSenior(userId);
		CompletableFuture<YanUserAgency> yanAgency = getYanAgency(userId);
		CompletableFuture<YanUserStudent> yanStudent = getYanStudent(userId);
		CompletableFuture<YanUserCounselor> yanCounselor = getYanCounselor(userId);
		CompletableFuture<YanUserTeacher> yanTeacher = getYanTeacher(userId);



		CompletableFuture.allOf(yanDetail, yanSenior, yanAgency, yanStudent, yanCounselor, yanTeacher).join();
		try {
			userDo.setYanUserSenior(yanSenior.get());
			userDo.setYanUserAgency(yanAgency.get());
			YanUserDetail yanUserDetail = yanDetail.get();
			if (Objects.nonNull(yanUserDetail)) {
				Map<String, String> sysUserSex = iSysDictDataService.selectDictMapByType("sys_user_sex");
				YanUserDetailVo yanUserDetailVo = yanUserDetail.transform(YanUserDetailVo.class);
				yanUserDetailVo.setSexName(sysUserSex.get(yanUserDetailVo.getSex()));
				userDo.setYanUserDetail(yanUserDetailVo);
			}
			userDo.setYanUserStudent(yanStudent.get());
			userDo.setYanUserCounselor(yanCounselor.get());
			userDo.setYanUserTeacher(yanTeacher.get());
			aggregate = AggregateFactory.createAggregate(userDo);
		} catch (Exception e) {
			e.printStackTrace();
		}

		return aggregate;
	}

	private CompletableFuture<YanUserDetail> getYanDetail(Long userId) {

		return CompletableFuture.supplyAsync(() -> {

			LambdaQueryWrapper<YanUserDetail> wrapper = new LambdaQueryWrapper<>();
			wrapper.eq(YanUserDetail::getUserId, userId).eq(YanUserDetail::getDelFlag, 0);

			return this.baseMapper.selectOne(wrapper);
		});
	}

	private CompletableFuture<SysUser> getSysUser(Long userId) {

		return CompletableFuture.supplyAsync(() -> {

			LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
			wrapper.eq(SysUser::getUserId, userId).eq(SysUser::getDelFlag, 0);

			return this.sysUserMapper.selectOne(wrapper);
		});
	}

	private CompletableFuture<YanUserStudent> getYanStudent(Long userId) {

		return CompletableFuture.supplyAsync(() -> {

			LambdaQueryWrapper<YanUserStudent> wrapper = new LambdaQueryWrapper<>();
			wrapper.eq(YanUserStudent::getUserId, userId).eq(YanUserStudent::getDelFlag, 0);
			wrapper.last("limit 1");
			return this.yanUserStudentMapper.selectOne(wrapper);
		});
	}

	private CompletableFuture<YanUserSenior> getYanSenior(Long userId) {

		return CompletableFuture.supplyAsync(() -> {

			LambdaQueryWrapper<YanUserSenior> wrapper = new LambdaQueryWrapper<>();
			wrapper.eq(YanUserSenior::getUserId, userId).eq(YanUserSenior::getDelFlag, 0);
			wrapper.last("limit 1");
			return this.yanUserSeniorMapper.selectOne(wrapper);
		});
	}

	private CompletableFuture<YanUserTeacher> getYanTeacher(Long userId) {

		return CompletableFuture.supplyAsync(() -> {

			LambdaQueryWrapper<YanUserTeacher> wrapper = new LambdaQueryWrapper<>();
			wrapper.eq(YanUserTeacher::getUserId, userId).eq(YanUserTeacher::getDelFlag, 0);
			wrapper.last("limit 1");
			return this.yanUserTeacherMapper.selectOne(wrapper);
		});
	}

	private CompletableFuture<YanUserAgency> getYanAgency(Long userId) {

		return CompletableFuture.supplyAsync(() -> {

			LambdaQueryWrapper<YanUserAgency> wrapper = new LambdaQueryWrapper<>();
			wrapper.eq(YanUserAgency::getUserId, userId).eq(YanUserAgency::getDelFlag, 0);
			wrapper.last("limit 1");

			return this.yanUserAgencyMapper.selectOne(wrapper);
		});
	}

	private CompletableFuture<YanUserCounselor> getYanCounselor(Long userId) {

		return CompletableFuture.supplyAsync(() -> {

			LambdaQueryWrapper<YanUserCounselor> wrapper = new LambdaQueryWrapper<>();
			wrapper.eq(YanUserCounselor::getUserId, userId).eq(YanUserCounselor::getDelFlag, 0);
			wrapper.last("limit 1");

			return this.yanUserCounselorMapper.selectOne(wrapper);
		});
	}

	/**
	 * 完善学生信息
	 *
	 * @param aggregate:
	 * @return
	 * @method saveStudentInfo
	 * @author M.simple
	 * @date 2023-11-25 11:54
	 * @version v2.0
	 */
	public Aggregate<YanUserDo> saveUser(Aggregate<YanUserDo> aggregate) {


		if (aggregate.isChanged()) {

			SysUser sysUser = aggregate.getRoot().transform(SysUser.class);
			if (Objects.nonNull(aggregate.getRoot().getUserId())) {

				if (aggregate.getRootSnapshot().getUserId() == null && Objects.nonNull(aggregate.getRoot().getUserId())) {
					this.sysUserMapper.insert(sysUser);
				} else {
					Set<String> changedFields = DataObjectUtils.getChangedFields(aggregate.getRootSnapshot(), aggregate.getRoot());
					if (!CollectionUtils.isEmpty(changedFields)) {
						this.sysUserMapper.updateById(sysUser);
					}

				}
			}else {
				this.sysUserMapper.insert(sysUser);
			}
			aggregate.getRoot().setUserId(sysUser.getUserId());


			if (Objects.nonNull(aggregate.getRoot().getYanUserDetail())) {

				aggregate.getRoot().getYanUserDetail().setUserId(aggregate.getRoot().getUserId());
				if (aggregate.getRootSnapshot().getYanUserDetail() == null && Objects.nonNull(aggregate.getRoot().getYanUserDetail())) {
					aggregate.getRoot().getYanUserDetail().setUserId(sysUser.getUserId());
					this.baseMapper.insert(aggregate.getRoot().getYanUserDetail());
				} else {
					Set<String> changedFields = DataObjectUtils.getChangedFields(aggregate.getRootSnapshot().getYanUserDetail(), aggregate.getRoot().getYanUserDetail());
					if (!CollectionUtils.isEmpty(changedFields)) {
						this.baseMapper.updateById(aggregate.getRoot().getYanUserDetail());
					}

				}
			}

			if (Objects.nonNull(aggregate.getRoot().getYanUserAgency())) {
				aggregate.getRoot().getYanUserAgency().setUserId(aggregate.getRoot().getUserId());
				if (aggregate.getRootSnapshot().getYanUserAgency() == null && Objects.nonNull(aggregate.getRoot().getYanUserAgency())) {
					aggregate.getRoot().getYanUserAgency().setUserId(sysUser.getUserId());
					this.yanUserAgencyMapper.insert(aggregate.getRoot().getYanUserAgency());
				} else {
					Set<String> changedFields = DataObjectUtils.getChangedFields(aggregate.getRootSnapshot().getYanUserAgency(), aggregate.getRoot().getYanUserAgency());
					if (!CollectionUtils.isEmpty(changedFields)) {
						this.yanUserAgencyMapper.updateById(aggregate.getRoot().getYanUserAgency());
					}

				}
			}

			if (Objects.nonNull(aggregate.getRoot().getYanUserSenior())) {
				aggregate.getRoot().getYanUserSenior().setUserId(aggregate.getRoot().getUserId());
				if (aggregate.getRootSnapshot().getYanUserSenior() == null && Objects.nonNull(aggregate.getRoot().getYanUserSenior())) {
					aggregate.getRoot().getYanUserSenior().setUserId(sysUser.getUserId());
					this.yanUserSeniorMapper.insert(aggregate.getRoot().getYanUserSenior());
				} else {
					Set<String> changedFields = DataObjectUtils.getChangedFields(aggregate.getRootSnapshot().getYanUserSenior(), aggregate.getRoot().getYanUserSenior());
					if (!CollectionUtils.isEmpty(changedFields)) {
						this.yanUserSeniorMapper.updateById(aggregate.getRoot().getYanUserSenior());
					}

				}
			}

			if (Objects.nonNull(aggregate.getRoot().getYanUserTeacher())) {
				aggregate.getRoot().getYanUserTeacher().setUserId(aggregate.getRoot().getUserId());
				if (aggregate.getRootSnapshot().getYanUserTeacher() == null && Objects.nonNull(aggregate.getRoot().getYanUserTeacher())) {
					aggregate.getRoot().getYanUserTeacher().setUserId(sysUser.getUserId());
					this.yanUserTeacherMapper.insert(aggregate.getRoot().getYanUserTeacher());
				} else {
					Set<String> changedFields = DataObjectUtils.getChangedFields(aggregate.getRootSnapshot().getYanUserTeacher(), aggregate.getRoot().getYanUserTeacher());
					if (!CollectionUtils.isEmpty(changedFields)) {
						this.yanUserTeacherMapper.updateById(aggregate.getRoot().getYanUserTeacher());
					}

				}
			}

			if (Objects.nonNull(aggregate.getRoot().getYanUserStudent())) {
				aggregate.getRoot().getYanUserStudent().setUserId(aggregate.getRoot().getUserId());
				if (aggregate.getRootSnapshot().getYanUserStudent() == null && Objects.nonNull(aggregate.getRoot().getYanUserStudent())) {
					aggregate.getRoot().getYanUserStudent().setUserId(sysUser.getUserId());
					this.yanUserStudentMapper.insert(aggregate.getRoot().getYanUserStudent());
					//notifyTask();
				} else {
					Set<String> changedFields = DataObjectUtils.getChangedFields(aggregate.getRootSnapshot().getYanUserStudent(), aggregate.getRoot().getYanUserStudent());
					if (!CollectionUtils.isEmpty(changedFields)) {
						this.yanUserStudentMapper.updateById(aggregate.getRoot().getYanUserStudent());
					}

				}
			}

			if (Objects.nonNull(aggregate.getRoot().getYanUserCounselor())) {
				aggregate.getRoot().getYanUserCounselor().setUserId(aggregate.getRoot().getUserId());
				if (aggregate.getRootSnapshot().getYanUserCounselor() == null && Objects.nonNull(aggregate.getRoot().getYanUserCounselor())) {
					aggregate.getRoot().getYanUserCounselor().setUserId(sysUser.getUserId());
					this.yanUserCounselorMapper.insert(aggregate.getRoot().getYanUserCounselor());
				} else {
					Set<String> changedFields = DataObjectUtils.getChangedFields(aggregate.getRootSnapshot().getYanUserCounselor(), aggregate.getRoot().getYanUserCounselor());
					if (!CollectionUtils.isEmpty(changedFields)) {
						this.yanUserCounselorMapper.updateById(aggregate.getRoot().getYanUserCounselor());
					}

				}
			}

		}

		return aggregate;
	}

	private void notifyTask() {

		try{
			AsyncManager.me().execute(new TimerTask(){
				@Override
				public void run() {
					yanUserDataAuthParseJob.handle();
				}
			});
		}catch (Exception e){
			log.error("=========notifyTask exec error=====", e);
		}
	}


	/**
	 * 完善学生信息
	 *
	 * @param cmd:
	 * @return
	 * @method saveStudentInfo
	 * @author M.simple
	 * @date 2023-11-25 11:54
	 * @version v2.0
	 */
	public YanUserDo saveStudentInfo(AddStudentInfoCmd cmd) {

		log.info("=============save student , cmd:{}===========", JSONObject.toJSONString(cmd));

		if(Objects.isNull(cmd.getUserId()) && StringUtils.isNull(cmd.getMobile())){
			throw new BaseException("参数错误，userId与mobile不能同时为空");
		}

		if (YanOpSourceStatusE.manage_web.getCode().equals(cmd.getOpSource())) {
			SysUser user = getSysUserByMobile(cmd.getMobile());
		}
		Aggregate<YanUserDo> aggregate = null;
		if (Objects.nonNull(cmd.getUserId())) {
			aggregate = getYanUserDo(cmd.getUserId());
		} else {
			aggregate = getYanUserDo(cmd.getMobile());
		}
		YanUserDo userDo = aggregate.getRoot();
		String password = this.iSysConfigService.selectConfigByKey("sys.user.initPassword");

		if (Objects.nonNull(cmd.getBachelorSchId()) && Objects.isNull(cmd.getBachelorSchName())) {
			YanSchool schoolDetail = yanSchoolService.getSchoolDetail(cmd.getBachelorSchId());
			//Map<String, String> map = iSysDictDataService.selectDictMapByType("agent_school");
			cmd.setBachelorSchName(schoolDetail.getSchoolName());
		}
		if (StringUtils.isNotEmpty(cmd.getBachelorSpeId()) && Objects.isNull(cmd.getBachelorSpeName())) {
			YanBachelorSpecial yanMasterSpecial = specialService.bachelorSecialDetail(cmd.getBachelorSpeId());
			cmd.setBachelorSpeName(yanMasterSpecial.getSpecialName());
		}

		if (Objects.nonNull(cmd.getTargetSchId()) && Objects.isNull(cmd.getTargetSchName())) {
			YanSchool schoolDetail = yanSchoolService.getSchoolDetail(cmd.getTargetSchId());
			cmd.setTargetSchName(schoolDetail.getSchoolName());
		}
		if (Objects.nonNull(cmd.getTargetSpeId()) && Objects.isNull(cmd.getTargetSpeName())) {
			YanMasterSpecial yanMasterSpecial = specialService.specialDetailById(cmd.getTargetSpeId());
			cmd.setTargetSpeName(yanMasterSpecial.getSpecialName());
		}

		userDo.fillStudentInfo(cmd, password);
		Aggregate<YanUserDo> yanUserDo = this.saveUser(aggregate);

		//绑定与代理的关系
		YanUserBind yanUserBind = YanUserBind.builder().bindType(YanUserBindTypeE.agency.getCode()).bindUid(yanUserDo.getRoot().getUserId()).targetUid(cmd.getAgencyUserId()).build();
		userBind(yanUserBind, cmd.getOpSource());

		//绑定与老师的关系
		YanUserBind teacherUserBind = YanUserBind.builder().bindType(YanUserBindTypeE.teacher.getCode()).bindUid(yanUserDo.getRoot().getUserId()).targetUid(cmd.getTeacherUserId()).build();
		userBind(teacherUserBind, cmd.getOpSource());

		return yanUserDo.getRoot();
	}

	public YanUserDo applyAgency(ApplyAgencyInfoCmd cmd) {

		if(Objects.isNull(cmd.getUserId()) && StringUtils.isNull(cmd.getMobile())){
			throw new BaseException("参数错误，userId与mobile不能同时为空");
		}

		if (YanOpSourceStatusE.manage_web.getCode().equals(cmd.getOpSource())) {
			SysUser user = getSysUserByMobile(cmd.getMobile());
		}
		Aggregate<YanUserDo> aggregate = null;
		if (Objects.nonNull(cmd.getUserId())) {
			aggregate = getYanUserDo(cmd.getUserId());
		} else {
			aggregate = getYanUserDo(cmd.getMobile());
		}
		String password = this.iSysConfigService.selectConfigByKey("sys.user.initPassword");
		if (Objects.nonNull(cmd.getCurrentSchId()) && Objects.isNull(cmd.getCurrentSchName())) {
			//Map<String, String> map = iSysDictDataService.selectDictMapByType("agent_school");
			YanSchool schoolDetail = yanSchoolService.getSchoolDetail(cmd.getCurrentSchId());
			cmd.setCurrentSchName(schoolDetail.getSchoolName());
		}
		if (Objects.nonNull(cmd.getCurrentSpeId()) && Objects.isNull(cmd.getCurrentSpeName())) {
			YanBachelorSpecial yanMasterSpecial = specialService.bachelorSecialDetail(cmd.getCurrentSpeId());
			cmd.setCurrentSpeName(yanMasterSpecial.getSpecialName());
		}
		aggregate.getRoot().applyAgency(cmd, password);

		Aggregate<YanUserDo> yanUserDo = this.saveUser(aggregate);

		//绑定与辅导员的关系
		YanUserBind yanUserBind = YanUserBind.builder().bindType("counselor").bindUid(yanUserDo.getRoot().getUserId()).targetUid(cmd.getCounselorUserId()).build();
		userBind(yanUserBind, cmd.getOpSource());

		//绑定与老师的关系
		YanUserBind teacherUserBind = YanUserBind.builder().bindType(YanUserBindTypeE.teacher.getCode()).bindUid(yanUserDo.getRoot().getUserId()).targetUid(cmd.getTeacherUserId()).build();
		userBind(teacherUserBind, cmd.getOpSource());

		return yanUserDo.getRoot();
	}

	public YanUserDo applyCounselor(ApplyCounselorInfoCmd cmd) {

		if(Objects.isNull(cmd.getUserId()) && StringUtils.isNull(cmd.getMobile())){
			throw new BaseException("参数错误，userId与mobile不能同时为空");
		}

		if (YanOpSourceStatusE.manage_web.getCode().equals(cmd.getOpSource())) {
			SysUser user = getSysUserByMobile(cmd.getMobile());
		}
		Aggregate<YanUserDo> aggregate = null;
		if (Objects.nonNull(cmd.getUserId())) {
			aggregate = getYanUserDo(cmd.getUserId());
		} else {
			aggregate = getYanUserDo(cmd.getMobile());
		}

		if (Objects.isNull(cmd.getCurrentSchName()) && Objects.nonNull(cmd.getCurrentSchId())) {
			YanSchool schoolDetail = yanSchoolService.getSchoolDetail(cmd.getCurrentSchId());
			cmd.setCurrentSchName(schoolDetail.getSchoolName());
		}
		if (Objects.isNull(cmd.getCurrentSpeName()) && Objects.nonNull(cmd.getCurrentSpeId())) {
			YanBachelorSpecial yanMasterSpecial = specialService.bachelorSecialDetail(cmd.getCurrentSpeId());
			cmd.setCurrentSpeName(yanMasterSpecial.getSpecialName());
		}
		String password = this.iSysConfigService.selectConfigByKey("sys.user.initPassword");
		aggregate.getRoot().applyCounselor(cmd, password);

		Aggregate<YanUserDo> yanUserDo = this.saveUser(aggregate);

		return yanUserDo.getRoot();
	}

	public YanUserDo applySenior(ApplySeniorInfoCmd cmd) {

		if(Objects.isNull(cmd.getUserId()) && StringUtils.isNull(cmd.getMobile())){
			throw new BaseException("参数错误，userId与mobile不能同时为空");
		}

		if (YanOpSourceStatusE.manage_web.getCode().equals(cmd.getOpSource())) {
			SysUser user = getSysUserByMobile(cmd.getMobile());
		}
		Aggregate<YanUserDo> aggregate = null;
		if (Objects.nonNull(cmd.getUserId())) {
			aggregate = getYanUserDo(cmd.getUserId());
		} else {
			aggregate = getYanUserDo(cmd.getMobile());
		}
		if (Objects.nonNull(cmd.getMasterSchId()) && Objects.isNull(cmd.getMasterSchName())) {
			YanSchool schoolDetail = yanSchoolService.getSchoolDetail(cmd.getMasterSchId());
			cmd.setMasterSchName(schoolDetail.getSchoolName());
		}
		if (Objects.nonNull(cmd.getMasterSpeId()) && Objects.isNull(cmd.getMasterSpeName())) {
			YanMasterSpecial yanMasterSpecial = specialService.specialDetailById(cmd.getMasterSpeId());
			cmd.setMasterSpeName(yanMasterSpecial.getSpecialName());
		}
		String password = this.iSysConfigService.selectConfigByKey("sys.user.initPassword");
		aggregate.getRoot().applySenior(cmd, password);

		Aggregate<YanUserDo> yanUserDo = this.saveUser(aggregate);

		return yanUserDo.getRoot();
	}

	public YanUserDo setMySpecial(SetMySpecialCmd cmd) {

		Aggregate<YanUserDo> aggregate = getYanUserDo(cmd.getUserId());
		aggregate.getRoot().setMySpecial(cmd);

		Aggregate<YanUserDo> yanUserDo = this.saveUser(aggregate);

		return yanUserDo.getRoot();
	}

	public List<UserAgencyVo> listAgency(PageAgencyQry qry) {

		List<UserAgencyVo> userAgencyVos = this.yanUserDetailMapper.listAgency(qry);
		return userAgencyVos;
	}

	public YanUserDo authAnency(AuthAgencyCmd cmd) {

		Aggregate<YanUserDo> yanUserDo = getYanUserDo(cmd.getUserId());
		YanUserDo root = yanUserDo.getRoot();
		root.authAgencyStatus(cmd);

		saveUser(yanUserDo);

		return root;
	}

	public List<UserSeniorVo> listSenior(PageSeniorQry qry) {

		List<UserSeniorVo> userSeniorVos = this.yanUserDetailMapper.listSenior(qry);
		userSeniorVos.forEach(x -> {
			x.setServiceList(JSONObject.parseArray(x.getServiceListStr(), YanJsonMapIo.class));
			x.setCertImgList(JSONObject.parseArray(x.getCertImgListStr(), String.class));
			x.setStatusName(YanCheckStatusE.code(x.getStatus()));
			List<String> keyList = x.getServiceList().stream().map(YanJsonMapIo::getKey).collect(Collectors.toList());
			x.setServiceKeyStr(Strings.join(keyList, ','));
		});
		return userSeniorVos;
	}

	public YanUserDo authSenior(AuthAgencyCmd cmd) {

		Aggregate<YanUserDo> yanUserDo = getYanUserDo(cmd.getUserId());
		YanUserDo root = yanUserDo.getRoot();
		root.authSeniorStatus(cmd);

		saveUser(yanUserDo);

		return root;
	}

	public YanUserBind userBind(YanUserBind cmd, String opSource) {

		cmd.setCreateBy(SecurityUtils.getUserId());

		if (Objects.isNull(cmd.getTargetUid())) {
			return cmd;
		}

		if (cmd.getBindUid().equals(cmd.getTargetUid()) && YanUserBindTypeE.agency.getCode().equals(cmd.getBindType())) {
			return cmd;
		}
		if (Objects.isNull(cmd.getBusinessKey())) {
			//判断该用户是否已存在绑定关系
			YanUserBind userBind = getUserBind(cmd.getBindType(), cmd.getBindUid());
			if (Objects.nonNull(userBind.getId())) {
				if (YanOpSourceStatusE.manage_web.getCode().equals(opSource) && !userBind.getTargetUid().equals(cmd.getTargetUid())) {
					userBind.setDelFlag(DelFlagEnum.I.getCode() + "");
					yanUserBindMapper.updateById(userBind);
				}else {
					return cmd;
				}

		}} else {
			//判断该用户是否已存在绑定关系
			YanUserBind userBindVo = getUserBindVo(cmd.getBindType(), cmd.getBindUid(), cmd.getBusinessKey());
			if (Objects.nonNull(userBindVo.getId())) {
				return cmd;
			}
		}

		if(YanUserBindTypeE.agency.getCode().equals(cmd.getBindType())){
			cmd.setBindStatus(YanCheckStatusE.checking.getCode());
		}else {
			cmd.setBindStatus(YanCheckStatusE.check_succ.getCode());
		}
		this.yanUserBindMapper.insert(cmd);

		return cmd;

	}

	@SneakyThrows
	public UserBindVo getUserBind(String bindType, Long userId) {

		return getUserBindVo(bindType, userId, null);
	}

	@SneakyThrows
	private UserBindVo getUserBindVo(String bindType, Long userId, String businessKey) {

		LambdaQueryWrapper<YanUserBind> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(YanUserBind::getBindType, bindType).eq(YanUserBind::getDelFlag, DelFlagEnum.O.getCode())
				.eq(YanUserBind::getBindUid, userId).eq(Objects.nonNull(businessKey), YanUserBind::getBusinessKey, businessKey)
				.eq(YanUserBind::getDelFlag, DelFlagEnum.O.getCode())
				.last("limit 1");

		YanUserBind yanUserBind = this.yanUserBindMapper.selectOne(queryWrapper);

		if (Objects.isNull(yanUserBind)) {
			return new UserBindVo();
		}

		UserBindVo userBindVo = yanUserBind.transform(UserBindVo.class);
		CompletableFuture<String> bindUserF = CompletableFuture.supplyAsync(() -> {

			SysUser bindUser = iSysUserService.selectUserById(userBindVo.getBindUid());
			if (Objects.isNull(bindUser)) {
				return null;
			}
			return bindUser.getNickName();
		});
		CompletableFuture<String> targetUserF = CompletableFuture.supplyAsync(() -> {

			SysUser bindUser = iSysUserService.selectUserById(userBindVo.getTargetUid());
			if (Objects.isNull(bindUser)) {
				return null;
			}
			return bindUser.getNickName();
		});
		CompletableFuture.allOf(bindUserF, targetUserF).join();
		userBindVo.setBindUidName(bindUserF.get());
		userBindVo.setTargetUidName(targetUserF.get());

		return userBindVo;
	}

	public YanUserBind getBusinessKeyBind(Long activityId, Long userId) {

		LambdaQueryWrapper<YanUserBind> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(YanUserBind::getBusinessKey, activityId).eq(YanUserBind::getDelFlag, DelFlagEnum.O.getCode())
				.eq(YanUserBind::getBindUid, userId);

		return this.yanUserBindMapper.selectOne(queryWrapper);
	}

	public YanUserDo saveUserDetail(YanUserDetail cmd) {

		Aggregate<YanUserDo> yanUserDo = getYanUserDo(cmd.getUserId());
		YanUserDo root = yanUserDo.getRoot();
		root.saveUserDetail(cmd);

		saveUser(yanUserDo);

		return root;
	}

	public List<StudentVo> listStudent(PageStudentQry qry) {


		return this.yanUserDetailMapper.listStudent(qry);
	}

	public List<UserCounselorVo> listCounselor(PageCounselorQry qry) {

		List<UserCounselorVo> userCounselorVos = this.yanUserDetailMapper.listCounselor(qry);
		return userCounselorVos;
	}

	public YanUserCommuLog saveCommuLog(YanUserCommuLog cmd) {

		if (Objects.isNull(cmd.getCommuId())) {
			yanUserCommuLogMapper.insert(cmd);
		} else {
			YanUserCommuLog log = getUserCommuLog(cmd.getCommuId());

			yanUserCommuLogMapper.updateById(log);
			cmd = log;
		}

		return cmd;
	}

	private YanUserCommuLog getUserCommuLog(Long commuId) {

		return yanUserCommuLogMapper.selectById(commuId);
	}

	public List<UserCommuLogVo> listCommuLog(PageCommuLogQry qry) {

		List<UserCommuLogVo> userCommuLogVos = this.yanUserDetailMapper.listCommuLog(qry);
		userCommuLogVos.forEach(x->{
			x.setCommuImgs(JSONObject.parseArray(x.getCommuImgsStr(), String.class));
			x.setCommuImgsStr(null);
		});
		return userCommuLogVos;
	}

	public UserVo linkTeacher(Long userId) {

		UserVo yanUserDo = getYanUserVo(userId);

		StudentVo yanUserStudent = yanUserDo.getYanUserStudent();
		YanUserTeacher teacher = null;
		Long teacherUserId = null;
		if(Objects.nonNull(yanUserStudent)){
			if(Objects.nonNull(yanUserStudent.getTeacherUserId())){
				teacherUserId = yanUserStudent.getTeacherUserId();
			}else {
				Long bachelorSchId = yanUserStudent.getBachelorSchId();
				String bachelorSpeId = yanUserStudent.getBachelorSpeId();
				if(Objects.nonNull(bachelorSchId) && Objects.nonNull(bachelorSpeId)){
					teacher = this.baseMapper.getLinkTeacher(bachelorSchId, bachelorSpeId);
				}
				if(Objects.isNull(teacher) && Objects.nonNull(bachelorSchId)){
					teacher = this.baseMapper.getLinkTeacher(bachelorSchId, null);
				}
				if(Objects.isNull(teacher) && Objects.nonNull(bachelorSchId)){
					teacher = this.baseMapper.getLinkTeacher(null, bachelorSpeId);
				}

				if(Objects.isNull(teacher)){
					teacher = this.baseMapper.getLinkTeacher(null, null);
				}
				teacherUserId = teacher.getUserId();
			}
		}else {
			teacher = this.baseMapper.getLinkTeacher(null, null);
			teacherUserId = teacher.getUserId();
		}

		return getYanUserVo(teacherUserId);
	}

	public YanUserDo applyTeacherInfo(ApplyTeacherInfoCmd cmd) {

		if(Objects.isNull(cmd.getUserId()) && StringUtils.isNull(cmd.getMobile())){
			throw new BaseException("参数错误，userId与mobile不能同时为空");
		}

		if (YanOpSourceStatusE.manage_web.getCode().equals(cmd.getOpSource())) {
			SysUser user = getSysUserByMobile(cmd.getMobile());
		}
		Aggregate<YanUserDo> aggregate = null;
		if (Objects.nonNull(cmd.getUserId())) {
			aggregate = getYanUserDo(cmd.getUserId());
		} else {
			aggregate = getYanUserDo(cmd.getMobile());
		}

		String password = this.iSysConfigService.selectConfigByKey("sys.user.initPassword");
		aggregate.getRoot().applyTeacherInfo(cmd, password);

		Aggregate<YanUserDo> yanUserDo = this.saveUser(aggregate);

		//绑定与辅导员的关系
		YanUserBind yanUserBind = YanUserBind.builder().bindType("manager").bindUid(yanUserDo.getRoot().getUserId()).targetUid(cmd.getCounselorUserId()).build();
		userBind(yanUserBind, cmd.getOpSource());

		return yanUserDo.getRoot();
	}

	public List<UserTeacherVo> listTeacher(PageTeacherQry qry) {

		List<UserTeacherVo> userTeacherVos = this.yanUserDetailMapper.listTeacher(qry);
		userTeacherVos.forEach(x->{
			x.setCurrentSchs(JSONObject.parseArray(x.getCurrentSchsStr(), YanJsonMapIo.class));
			x.setCurrentSpes(JSONObject.parseArray(x.getCurrentSpesStr(), YanJsonMapIo.class));

		});
		return userTeacherVos;
	}

	@Transactional
	public void dataAuth(UserDataAuthCmd cmd) {

		Aggregate<YanUserDo> yanUserDo = getYanUserDo(cmd.getUserId());
		yanUserDo.getRoot().fillStaffUser(cmd);
		saveUser(yanUserDo);

		YanUserDetailVo yanUserDetail = yanUserDo.getRoot().getYanUserDetail();
		dataAuthParse(yanUserDetail);
	}

	public void dataAuthParse(YanUserDetail yanUserDetail) {

		List<DataTypeAuthIo> dataAuth = JSONObject.parseArray(JSONObject.toJSONString(yanUserDetail.getDataAuth()), DataTypeAuthIo.class);

		List<YanUserBindTypeE> types = List.of(YanUserBindTypeE.data_business,
				YanUserBindTypeE.data_agency,
				YanUserBindTypeE.data_xiaoke,
				YanUserBindTypeE.data_mokao,
				YanUserBindTypeE.student_mobile);

		Map<String, DataTypeAuthIo> map = new HashMap<>();
		if(Objects.nonNull(dataAuth)){
			for (DataTypeAuthIo dataTypeAuthIo : dataAuth) {
				map.put(dataTypeAuthIo.getDataType(), dataTypeAuthIo);
			}
		}

		for (YanUserBindTypeE type : types) {
			List<Long> authUserIdList = new ArrayList<>();
			if (map.containsKey(type.getCode())) {
				DataTypeAuthIo x = map.get(type.getCode());
				authUserIdList = x.getAuthUserIdList();
				if("all".equals(x.getAuthType())){

					if(YanUserBindTypeE.data_business.getCode().equals(x.getDataType())){
						authUserIdList = this.baseMapper.selectAllTeacherId();
					}else if(YanUserBindTypeE.data_agency.getCode().equals(x.getDataType())){
						List<Long> yanUserAgencys= this.baseMapper.selectAllAgencyId();
						authUserIdList = yanUserAgencys;
					}else if(YanUserBindTypeE.student_mobile.getCode().equals(x.getDataType())){
						List<Long> yanUserAgencys= this.baseMapper.selectAllStudentId();
						authUserIdList = yanUserAgencys;
					}else {
						authUserIdList = new ArrayList<>();
					}
				}else if("school_area".equals(x.getAuthType())){

					if(YanUserBindTypeE.data_business.getCode().equals(x.getDataType())){
						authUserIdList = this.baseMapper.selectTeacherBySchoolArea(x.getAuthUserIdList());
					}else if(YanUserBindTypeE.data_agency.getCode().equals(x.getDataType())){
						List<Long> yanUserAgencys= this.baseMapper.selectAgencyBySchoolArea(x.getAuthUserIdList());
						authUserIdList = yanUserAgencys;
					}else if(YanUserBindTypeE.student_mobile.getCode().equals(x.getDataType())){
						List<Long> yanUserAgencys= this.baseMapper.selectStudentBySchoolArea(x.getAuthUserIdList());
						authUserIdList = yanUserAgencys;
					} else {
						authUserIdList = new ArrayList<>();
					}
				}else if("teacher".equals(x.getAuthType())){
					if(YanUserBindTypeE.data_agency.getCode().equals(x.getDataType())){
						authUserIdList = this.baseMapper.selectAgencyByTeacherIds(x.getAuthUserIdList());
					}else if(YanUserBindTypeE.student_mobile.getCode().equals(x.getDataType())){
						authUserIdList = this.baseMapper.selectStudentByTeacherIds(x.getAuthUserIdList());
					}
				}
			}
			updateAuthBind(yanUserDetail.getUserId(), type.getCode(), authUserIdList);
		}
	}

	private void updateAuthBind(Long userId, String dataType, List<Long> authUserIdList) {
		LambdaQueryWrapper<YanUserBind> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(YanUserBind::getTargetUid, userId)
				.eq(YanUserBind::getBindType, dataType)
				.eq(YanUserBind::getDelFlag, "0");
		List<YanUserBind> existYanUserBinds = this.yanUserBindMapper.selectList(queryWrapper);
		for (YanUserBind existYanUserBind : existYanUserBinds) {
			if (authUserIdList.contains(existYanUserBind.getBindUid())) {
				authUserIdList.remove(existYanUserBind.getBindUid());
			} else {
				existYanUserBind.setDelFlag("1");
				this.yanUserBindMapper.updateById(existYanUserBind);
			}
		}
		authUserIdList.forEach(y->{
			YanUserBind userBind = YanUserBind.builder().bindType(dataType).bindUid(y).targetUid(userId).build();
			this.yanUserBindMapper.insert(userBind);
		});
	}

	public List<YanUserDetail> listTeacherDataNeedParse() {

		LambdaQueryWrapper<YanUserDetail> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.isNotNull(YanUserDetail::getDataAuth).eq(YanUserDetail::getDelFlag, "0");
		return this.yanUserDetailMapper.selectList(queryWrapper);
	}

	public List<UserBindVo> listUserBind(PageUserBindQry qry) {

		return yanUserDetailMapper.listUserBind(qry);
	}

	public YanUserBind checkUserBind(BindUserCheckCmd cmd) {

		YanUserBind yanUserBind = this.yanUserBindMapper.selectById(cmd.getBindId());
		if(YanCheckStatusE.check_fail.getCode().equals(cmd.getBindStatus())){
			yanUserBind.setRemark(cmd.getRemark());
			yanUserBind.setBindStatus(cmd.getBindStatus());
		}else if(YanCheckStatusE.check_succ.getCode().equals(cmd.getBindStatus())){
			yanUserBind.setRemark(cmd.getRemark());
			yanUserBind.setBindStatus(cmd.getBindStatus());
		}

		yanUserBind.setCheckBy(SecurityUtils.getUserId());
		yanUserBind.setCheckTime(LocalDateTime.now());

		this.yanUserBindMapper.updateById(yanUserBind);

		return yanUserBind;
	}

	public List<YanUserBind> studentBind(StudentBindCmd cmd, String code) {

		List<YanUserBind> list = new ArrayList<>();

		Aggregate<YanUserDo> yanUserDo = getYanUserDo(cmd.getBindUid());
		UserVo yanUserVo = getYanUserVo(cmd.getTargetUid());
		if(Objects.isNull(yanUserVo)){
			return null;
		}

		if(Objects.nonNull(yanUserVo.getYanUserAgency())){
			YanUserBind yanUserBind = YanUserBind.builder().bindUid(cmd.getBindUid()).targetUid(cmd.getTargetUid()).bindType(YanUserBindTypeE.agency.getCode()).build();
			list.add(this.userBind(yanUserBind, code));

			if(Objects.isNull(yanUserVo.getYanUserTeacher()) && Objects.nonNull(yanUserVo.getYanUserStudent().getTeacherUserId())){
				yanUserBind = YanUserBind.builder().bindUid(cmd.getBindUid()).targetUid(yanUserVo.getYanUserStudent().getTeacherUserId()).bindType(YanUserBindTypeE.teacher.getCode()).build();
				list.add(this.userBind(yanUserBind, code));
				yanUserDo.getRoot().linkTeacher();
			}
		}

		if(Objects.nonNull(yanUserVo.getYanUserTeacher())){
			YanUserBind yanUserBind = YanUserBind.builder().bindUid(cmd.getBindUid()).targetUid(cmd.getTargetUid()).bindType(YanUserBindTypeE.teacher.getCode()).build();
			list.add(this.userBind(yanUserBind, code));
			yanUserDo.getRoot().linkTeacher();
		}

		saveUser(yanUserDo);
		return list;
	}

	public List<SysDictData> getDataAuthSchoolList(Long userId, String dataType) {

		UserVo yanUserVo = getYanUserVo(userId);
		List<DataTypeAuthIo> dataAuth = yanUserVo.getYanUserDetail().getDataAuth();
		if(Objects.isNull(dataAuth)){
			return null;
		}
		DataTypeAuthIo dataTypeAuthIo = dataAuth.stream().filter(x -> dataType.equals(x.getDataType())).findFirst().orElse(null);
		if(Objects.isNull(dataTypeAuthIo)){
			return null;
		}
		List<SysDictData> agent_school = sysDictTypeService.selectDictDataByType("agent_school");
		switch (dataTypeAuthIo.getAuthType()){
			case "all":
				//1.如果配置为all,获取所有的校区
				return agent_school;
			case "school_area":
				//2.如果配置为校区，获取配置的校区
				List<Long> schoolAreaIds = dataTypeAuthIo.getAuthUserIdList();
				return agent_school.stream().filter(x->schoolAreaIds.contains(Long.valueOf(x.getDictValue()))).collect(Collectors.toList());
			case "teacher":
				//3.如果配置为老师，获取老师所在校区
				List<SysUser> sysUsers = sysUserMapper.selectUserByIds(dataTypeAuthIo.getAuthUserIdList());
				if(CollectionUtils.isEmpty(sysUsers)){
					return null;
				}
				schoolAreaIds = sysUsers.stream().map(SysUser::getDeptId).collect(Collectors.toList());
				return agent_school.stream().filter(x->schoolAreaIds.contains(Long.valueOf(x.getDictValue()))).collect(Collectors.toList());

		}

		//biSchoolAgencyDataVos = Optional.ofNullable(biSchoolAgencyDataVos).orElse(new ArrayList<>());
		return null;
	}

	public UserVo userAuthCheck(UserAuthQry userAuthQry) {
		Long userId = SecurityUtils.getUserId();
		LambdaQueryWrapper<YanUserBind> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(YanUserBind::getBindUid, userAuthQry.getStudentUid());
		queryWrapper.eq(YanUserBind::getTargetUid, userId);
		queryWrapper.eq(YanUserBind::getDelFlag, DelFlagEnum.O.getCode());
		queryWrapper.eq(YanUserBind::getBindType, userAuthQry.getBindType());
		queryWrapper.last("limit 1");
		YanUserBind userBind = yanUserBindMapper.selectOne(queryWrapper);
		if(Objects.isNull(userBind)){
			return null;
		}

		return getYanUserVo(userAuthQry.getStudentUid());
	}
}
